#include "Server.h"
#include "./common/SDS.h"
#include "./common/YXConfig.h"
#include "./common/YXConstant.h"
#include "./common/YXFile.h"
#include "./common/YXIO.h"
#include "./common/YXLog.h"
#include "./common/YXNet.h"
#include "./common/YXThreadPool.h"
#include "./common/YXTime.h"
#include "../include/mysql/mysql.h"
#include "Console.h"
#include "Http.h"
#include "HttpClient.h"
#include "HttpFixedResponse.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
#include "utils/BucketsAccess.h"
#include "./local/buckets/BucketsMeta.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "service/ObjectsService.h"

Server server;

/**
 * 接收客户端请求
 */
void accept_request(EventLoop *el, int fd, int mask, void *client_data) {
    struct sockaddr_in client_address;
    int                addrlen   = sizeof(client_address);
    int                client_fd = accept(fd, (struct sockaddr *) &client_address, &addrlen);
    if (client_fd == -1) {
        logErrno();
        return;
    }
    if (client_fd > SERVER_DEFAULT_MAX_CLIENTS) {
        close(client_fd);
        return;
    }
    if (create_client(client_fd) == NULL) {
        close(client_fd);
        return;
    }
    logDebug("A new client connected: %s:%d", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));
}

/**
 * 读取客户端请求
 */
void read_reqeust(EventLoop *el, int fd, int mask, void *client_data) {
    int      n;
    Client  *client  = client_data;
    Request *request = client->request;

    while (1) {
        if (request->state == HTTP_REQUEST_STATE_PARSE_LINE || request->state == HTTP_REQUEST_STATE_PARSE_HEADER) {
            n = read_line(fd, client->input_buffer);
            if (n == READ_SUCCESS) {
                client->last_send_time = mstime();
                parse_request(el, client);
                if (request->state == HTTP_REQUEST_STATE_PARSE_COMPLETED) {
                    break;
                }
                continue;
            }
            if (n == READ_UNABLE) {
                send_response_bad_request(el, client, "The line of request is too long");
                return;
            }
        } else {
            n = read_once(fd, request->body);
            if (n == READ_SUCCESS) {
                client->last_send_time = mstime();
                parse_request(el, client);
                if (request->state == HTTP_REQUEST_STATE_PARSE_COMPLETED) {
                    break;
                }
                continue;
            }
        }
        if (n == READ_EXIT || n == READ_FAILED) {
            client_full_free(client);
        }
        return;
    }
}

/**
 * 发送响应给客户端
 */
void send_response(EventLoop *el, int fd, int mask, void *client_data) {
    int       n;
    Client   *client   = client_data;
    Response *response = client->response;
    sds       buf      = client->input_buffer;

    // 发送状态行和响应头
    if (sds_len(buf)) {
        n = send(fd, buf + client->bufpos, sds_len(buf) - client->bufpos, 0);
        if (n == 0) {
            client_full_free(client);
        } else if (n == -1) {
            if (errno != EAGAIN) {
                client_full_free(client);
            }
        } else {
            client->bufpos += n;
            sds_update_len(buf, sds_len(buf) - n);
            // sds_incr_len(buf, -n);
        }
        return;
    }

    // 写入响应体
    if (response->type == HTTP_RESPONSE_SYNC) {
        if (sds_len(response->body)) {
            n = send(fd, response->body + response->bodypos, sds_len(response->body), 0);
            if (n == 0) {
                client_full_free(client);
                return;
            } else if (n == -1) {
                if (errno != EAGAIN) {
                    client_full_free(client);
                }
                return;
            } else {
                response->bodypos += n;
                sds_update_len(response->body, sds_len(response->body) - n);
                // sds_incr_len(response->body, -n);
            }
        }
        if (sds_len(response->body) == 0) {
            if (response->staus != 200) {
                client_full_free(client);
                return;
            }
            net_delete_file_event(el, fd, YX_NET_WRITABLE);
            reset_client(client);
        }
    } else {
        // 取消监听可写事件
        net_delete_file_event(el, client->fd, YX_NET_WRITABLE);
        // 标记Client为busy, 防止被回收
        set_client_is_busy(client);
        // 异步发送响应
        yxThreadPoolAddTask(server.thread_pool, async_send_response, client);
    }
}

int get_file(Request *request, Response *response) {
    /* 获取文件前鉴权 */
    // if (bucket_access_check(request, response) == YX_ERR) {
    //     return YX_ERR;
    // }

    // 判断文件是否存在, 并设置文件基本信息
    if (get_file_basic_info(FILE_RESOURCE_PATH_PREFIX, request, response) != YX_OK) {
        return YX_ERR;
    }

    set_async_response(response, async_response_callback);

    return YX_OK;
}

/**
 * 获取文件基本信息，如文件大小、MIME类型等
 * 若文件不存在，则会设置对应响应信息, 并返回YX_ERR
 * （待优化）
 */
int get_file_basic_info(char *prefix_path, Request *request, Response *response) {
    char full_path[HTTP_REQUEST_FULL_PATH_MAX_LENGTH];
    sprintf(full_path, "%s%s", prefix_path, request->path);

    struct stat st;
    if (stat(full_path, &st) == -1) {
        set_response_not_found(response);
        return YX_ERR;
    }
    response->content_length = st.st_size;

    // 根据文件扩展名设置MIME类型
    char *ext = strrchr(request->path, '.');
    if (strcmp(ext, ".png") == 0) {
        response->content_type = MIME_TYPE_PNG;
    } else if (strcmp(ext, ".jpg") == 0) {
        response->content_type = MIME_TYPE_JPEG;
    } else if (strcmp(ext, ".jpeg") == 0) {
        response->content_type = MIME_TYPE_JPEG;
    } else if (strcmp(ext, ".gif") == 0) {
        response->content_type = MIME_TYPE_GIF;
    } else if (strcmp(ext, ".html") == 0) {
        response->content_type = MIME_TYPE_HTML;
    } else if (strcmp(ext, ".css") == 0) {
        response->content_type = MIME_TYPE_CSS;
    } else if (strcmp(ext, ".js") == 0) {
        response->content_type = MIME_TYPE_JS;
    } else {
        response->content_type = MIME_TYPE_TEXT;
    }

    return YX_OK;
}

/**
 * 返回YX_OK表示读取请求体完毕或出现了错误，返回YX_ERR表示需要继续读取请求体
 * （待优化）
 */
#define PARSE_HTTP_REQUEST_POST_FILE_WRITE ROUTE_DEFAULT_STATE + 1

int post_file(Request *request, Response *response) {

    /* 获取文件前鉴权 */
    // if (bucket_access_check(request, response) == YX_ERR) {
    //     return YX_OK;
    // }

    char full_path[256], temp[256];
    sprintf(full_path, "%s%s", FILE_RESOURCE_PATH_PREFIX, request->path);

    if (request->route_state == ROUTE_DEFAULT_STATE) {
        // 首先判断文件是否存在
        if (yx_file_is_exist(full_path)) {
            set_response_bad_request(response, "File already exists");
            return YX_OK;
        }
        // 遍历整个路径，尝试创建每一级目录
        for (int i = 2; full_path[i] != '\0'; i++) {
            if (full_path[i] == '/') {
                // 复制子路径
                strncpy(temp, full_path, i);
                temp[i] = '\0';
                // 尝试创建子路径目录
                if (yx_file_mkdir(temp) == -1) {
                    // 如果创建失败，检查是否因为目录已存在
                    if (errno != EEXIST) {
                        set_response_bad_request(response, "Directory creation failed");
                        return YX_OK;
                    }
                }
            }
        }
        request->route_state = PARSE_HTTP_REQUEST_POST_FILE_WRITE;
    }
    FILE *fp = fopen(full_path, "ab");
    if (fp == NULL) {
        set_response_bad_request(response, "File open failed");
        return YX_OK;
    }

    // 写入文件
    int cnt = 0, n;
    while ((n = fwrite(request->body + cnt, 1, sds_len(request->body) - cnt, fp)) > 0) {
        cnt += n;
    }
    sds_incr_len(request->body, -cnt);
    request->content_length -= cnt;
    // 关闭文件
    fclose(fp);

    if (request->content_length)
        return YX_ERR;
    char* name = sds_get_str_range(request->path, sds_index_last_of(request->path, '/') + 1, sds_len(request->path));
    char* parent = sds_get_str_range(request->path, 0, sds_index_last_of(request->path, '/') - 1);
    postObject(name, request->content_type, parent, request->content_length, mstime());
    return YX_OK;
}

static void handling_args(int argc, char *argv[]) {
    if (!yx_file_is_exist(FILE_RESOURCE_PATH_PREFIX)) {
        if (yx_file_mkdir(FILE_RESOURCE_PATH_PREFIX) == YX_ERR) {
            logFatal("mkdir %s failed: %s", FILE_RESOURCE_PATH_PREFIX, strerror(errno));
        }
    }
    // 初始化全局元数据目录（如果不存在）
    bucket_global_meta_create_meta();
}

static void init_server() {
    server.connection_timeout =
            yxConfig.chooseIntProperty("server.connection-timeout", SERVER_DEFAULT_CONNETION_TIMEOUT);
    server.el = net_create_event_loop(yxConfig.chooseIntProperty("server.max-clients", SERVER_DEFAULT_MAX_CLIENTS) +
                                      EVENTLOOP_FDSET_INCR);
    server.client_list   = client_list_create();
    server.client_status = malloc(SERVER_DEFAULT_MAX_CLIENTS);
    memset(server.client_status, 0, SERVER_DEFAULT_MAX_CLIENTS);

    server.fd = net_create_server_socket(yxConfig.chooseStrProperty("server.host", SERVER_DEFAULT_HOST),
                                         yxConfig.chooseIntProperty("server.port", SERVER_DEFAULT_PORT));
    if (net_create_file_event(server.el, server.fd, YX_NET_READABLE, accept_request, NULL) == YX_ERR) {
        logErrno();
        exit(EXIT_FAILURE);
    }

    // 初始化线程池
    server.thread_pool =
            yxThreadPoolCreate(yxConfig.chooseIntProperty("server.thread-pool-size", SERVER_DEFAULT_THREAD_POOL_SIZE));
}

static void loop(EventLoop *el) {
    Client             *client;
    ClientListIterator *iter = client_list_iterator_create(server.client_list);

    while (!el->stop) {
        int nums = yxApiPoll(el, 2000);
        for (int i = 0; i < nums; i++) {
            FileEvent *file_event = &el->events[el->fired_events[i].fd];
            int        fd         = el->fired_events[i].fd;
            int        mask       = el->fired_events[i].mask;

            if (file_event->mask & mask & YX_NET_READABLE) {
                file_event->read_proc(el, fd, mask, file_event->client_data);
            }
            if (file_event->mask & mask & YX_NET_WRITABLE) {
                file_event->write_proc(el, fd, mask, file_event->client_data);
            }
        }

        /* 清理客户端资源 */
        client_list_iterator_reset(iter);
        while ((client = client_list_iterator_next(iter)) != NULL) {
            // 正常情况到这里还处于 DISCONNECTED 状态的客户端是 RESPONSE 类型为 ASYNC 的客户端
            if (client_get_status(client) == CLIENT_STATUS_DISCONNECTED) {
                client_remain_free(client);
            } else if (mstime() - client->last_send_time > server.connection_timeout) {
                if (client_get_status(client) == CLIENT_STATUS_BUSY) {
                    continue;
                }
                client_full_free(client);
            }
        }
    }
}

__attribute__((constructor(YX_CONFIG_INIT_PRIORITY - 1))) void mt_ascii_art() {
    printf("                        ,----, \n"
           "          ____        ,/   .`| \n"
           "        ,'  , `.    ,`   .'  : \n"
           "     ,-+-,.' _ |  ;    ;     / \n"
           "  ,-+-. ;   , ||.'___,/    ,'  \n"
           " ,--.'|'   |  ;||    :     |   \n"
           "|   |  ,', |  ':;    |.';  ;   \n"
           "|   | /  | |  ||`----'  |  |   \n"
           "'   | :  | :  |,    '   :  ;   \n"
           ";   . |  ; |--'     |   |  '   \n"
           "|   : |  | ,        '   :  |   \n"
           "|   : '  |/         ;   |.'    \n"
           ";   | |`-'          '---'      \n"
           "|   ;/                         \n"
           "'---'                          \n");
}

int main(int argc, char *argv[]) {
#if defined(__linux__)
    signal(SIGPIPE, SIG_IGN);
#endif
    // 处理命令行参数
    handling_args(argc, argv);
    // 开启控制台
    start_console();
    // 初始化服务器
    init_server();
    // 开启事件循环
    loop(server.el);

    return 0;
}
